#ifndef ACTOR_H
#define ACTOR_H 1

#include <string>
#include <fstream>
#include <map>
#include <vector>
#include <panel.h>
#include "object.h"
#include "tile.h"
#include "item.h"
#include "extras.h"
using std::vector;
using std::map;
using std::string;
using std::ofstream;

struct AttackInfo{
	AttackInfo() : cost(0),dice(0),type(NORMAL),desc(""){}
	AttackInfo(int cost,int dice,DamageType type,string desc) : cost(cost),dice(dice),type(type),desc(desc){}
	void Define(int cost_,int dice_,DamageType type_,string desc_){ cost=cost_; dice=dice_; type=type_; desc=desc_; }
	int cost;
	int dice;
	DamageType type;
	string desc;
};

class Actor : public Object{
private:
	int gold;
	bool allied;
	AIType AI;
	vector<Actor*> minions;
	int maxhp,curhp;
	int maxmp,curmp;
	int speed,size;
	Item* weapon;
	Item* talisman;
	vector<Item*> inv;
	vector<SpellType> spells;
	map<AttrType,int> has_attr;
	vector<int> attack;
	Tile* player_seen;
	Actor* target;
	string nickname; //it seems that strings are  automatically initialized to blank - i've been doing it the hard way
public:
	Actor();
	Actor(Actor& in,int r,int c);
	string AName();
	string TheName();
	void LoseGold(int num){ gold -= num; }
	void GainGold(int num){ gold += num; }
	int Gold(){ return gold; }
	int Speed(){ return speed; }
	int Size(){ return size; }
	bool IsAllied(){ return allied; }
	int HasAttr(AttrType attr){ return has_attr[attr]; }
	int AttackNumber(int x){ return attack[x]; }
	void MakeAllied(bool ally){ allied = ally; }
	string Nickname(){ return nickname; }
	void CloneSelf(int r,int c);
	void Define(int id_,string name_,char symbol_,int color_,AIType AI_,int maxhp_,int speed_);
	void SetNickname(string in){ nickname = in; }
	void AddAttack(int idx){ attack.insert(attack.end(),idx); }
	void RFG(bool check_torch=false);
	void Move(int r,int c,bool swap=false);
	bool HasLOS(int r,int c);
	bool HasLOS(Object* ptr){ return HasLOS(ptr->Row(),ptr->Col()); }
	bool CanSee(Object* ptr);
	bool CanSee(int r,int c);
	bool CanSeeOpaque(Object* ptr);
	Actor* LOELine(Object* ptr,int num);
	string YouAre(); //returns either "The (foo) is" or "You are"
	string You(string in,bool ends_in_es=false); //note the proper usage: You("cast") returns either "The (foo) casts" or "You cast"
	void Input();
	void InpPC();
	void InpAI();
	//bool Recover();
	/*bool AI_AttemptStep(int rowchange,int colchange,bool extend=true);
	bool AI_Advance(Object* ptr);
	bool AI_Flee(Object* ptr);*/
	//bool AI_Sidestep(Object* ptr);
	bool AI_Step(Object* ptr,bool flee=false);
	bool AI_MoveOrOpen(int r,int c);
	bool Attack(int attack_idx,Actor* ptr);
	void FireArrow(Tile* ptr);
	bool IsHit(int plus_to_hit);
	void TakeDamage(DamageType type,int dmg,Actor* source);
	SpellType SelectSpell(string in);
	void GainSpell(SpellType spell){ spells.insert(spells.end(),spell); }
//	void LoseSpell(SpellType spell){ has_spell[spell] -= num; }
	void GainAttr(AttrType attr,int num=1){ has_attr[attr] += num; }
	void LoseAttr(AttrType attr,int num=1){ has_attr[attr] -= num; }
	void GetItem(Item* ptr){ inv.insert(inv.end(),ptr); }
	Item* ItemPtr(int num);
	void LoseItem(Item* ptr);
	void DisplayInv();
	Item* SelectItem(string in);
	void DisplayEquipment();
	void DisplayStats(bool lower_only=false);
	void RemoveTarget(Actor* ptr);
	Tile* GetTarget(string initial_msg="Move cursor to choose target, then press 't' or Enter. ");
	int GetDirection(bool orth=false);
	Actor* ActorInDirection(int dir);
	Tile* TileInDirection(int dir);
	int DirectionOfOnly(string tilename,bool ignore_actors,bool orth=false);
	int ActorsAround();
	void RefreshLevel();
	void Q0();
	void Q1();
	void QS();
	void AddMinion(Actor* ptr){ minions.insert(minions.end(),ptr); }
	void RemoveMinion(Actor* ptr);
	bool PayMP(int num);
	void Summon(int r,int c);
	void Unsummon();
	string SpellName(SpellType spell);
	int SpellCost(SpellType spell);
	void CastSpell(SpellType spell,Tile* ptr=NULL);
};

#endif

